import 'package:backend.core/core/domain/entities/google_play/google_play_purchased_subscription_info.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_purchased_subscription_transaction.dart';
import 'package:backend.core/core/domain/errors/failures.dart';
import 'package:backend.core/core/domain/repositories/google_play_purchased_item_info_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/google_play_transaction_repository/repository.dart';
import 'package:backend.core/core/domain/utils/either_extension.dart';
import 'package:dartz/dartz.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_purchased_item.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_purchased_item_identifier.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_revoked_purchased_item.dart';
import 'package:backend.purchases/domain/helpers/google_play/create_google_play_purchased_subscription_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_purchased_subscription_info_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_purchased_subscription_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_purchased_subscription_transaction_from_revoked_purchased_item.dart';
import 'package:backend.purchases/domain/repositories/google_play_api_purchased_item_repository/repository.dart';

part 'failures.dart';

abstract class HandleSubscriptionDeferredGooglePlayApiNotification {
  Future<Either<SubscriptionDeferredGooglePlayApiNotificationHandlingFailure, void>> call({
    required GooglePlayApiPurchasedItemIdentifier purchasedItemIdentifier,
  });
}

class HandleSubscriptionDeferredGooglePlayApiNotificationImpl
    implements HandleSubscriptionDeferredGooglePlayApiNotification {
  const HandleSubscriptionDeferredGooglePlayApiNotificationImpl({
    required GooglePlayPurchasedItemInfoRepository googlePlayPurchasedItemInfoRepository,
    required GooglePlayTransactionRepository
        googlePlayTransactionRepository,
    required GooglePlayApiPurchasedItemRepository googlePlayApiPurchasedItemRepository,
    required CreateGooglePlayPurchasedSubscriptionTransactionFromApiOne
        createGooglePlayPurchasedSubscriptionTransactionFromApiOne,
    required UpdateGooglePlayPurchasedSubscriptionInfoFromApiOne
        updateGooglePlayPurchasedSubscriptionInfoFromApiOne,
    required UpdateGooglePlayPurchasedSubscriptionTransactionFromApiOne
        updateGooglePlayPurchasedSubscriptionTransactionFromApiOne,
    required UpdateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem
        updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem,
  })  : _googlePlayPurchasedItemInfoRepository = googlePlayPurchasedItemInfoRepository,
        _googlePlayTransactionRepository =
            googlePlayTransactionRepository,
        _googlePlayApiPurchasedItemRepository = googlePlayApiPurchasedItemRepository,
        _createGooglePlayPurchasedSubscriptionTransactionFromApiOne =
            createGooglePlayPurchasedSubscriptionTransactionFromApiOne,
        _updateGooglePlayPurchasedSubscriptionInfoFromApiOne =
            updateGooglePlayPurchasedSubscriptionInfoFromApiOne,
        _updateGooglePlayPurchasedSubscriptionTransactionFromApiOne =
            updateGooglePlayPurchasedSubscriptionTransactionFromApiOne,
        _updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem =
            updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem;

  final GooglePlayPurchasedItemInfoRepository _googlePlayPurchasedItemInfoRepository;
  final GooglePlayTransactionRepository _googlePlayTransactionRepository;
  final GooglePlayApiPurchasedItemRepository _googlePlayApiPurchasedItemRepository;

  final CreateGooglePlayPurchasedSubscriptionTransactionFromApiOne
      _createGooglePlayPurchasedSubscriptionTransactionFromApiOne;
  final UpdateGooglePlayPurchasedSubscriptionInfoFromApiOne
      _updateGooglePlayPurchasedSubscriptionInfoFromApiOne;
  final UpdateGooglePlayPurchasedSubscriptionTransactionFromApiOne
      _updateGooglePlayPurchasedSubscriptionTransactionFromApiOne;
  final UpdateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem
      _updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem;

  @override
  Future<Either<SubscriptionDeferredGooglePlayApiNotificationHandlingFailure, void>> call({
    required GooglePlayApiPurchasedItemIdentifier purchasedItemIdentifier,
  }) async {
    final futureResults = await Future.wait([
      _googlePlayPurchasedItemInfoRepository.findPurchasedItemInfoByToken(
        purchaseToken: purchasedItemIdentifier.purchaseToken,
      ),
      _googlePlayApiPurchasedItemRepository.getPurchasedSubscription(
        purchasedItemIdentifier: purchasedItemIdentifier,
      ),
    ]);

    var i = 0;
    final purchasedSubscriptionInfo = futureResults[i++] as GooglePlayPurchasedSubscriptionInfo?;
    final failureOrUpdatedApiPurchasedSubscription = futureResults[i++] as Either<
        GooglePlayApiPurchasedSubscriptionGettingFailure, GooglePlayApiPurchasedSubscription>;

    if (purchasedSubscriptionInfo == null) {
      return right(null);
    }

    if (failureOrUpdatedApiPurchasedSubscription.isLeft()) {
      return left(const SubscriptionDeferredGooglePlayApiNotificationHandlingFailure());
    }

    final updatedApiPurchasedSubscription = failureOrUpdatedApiPurchasedSubscription.asRight();

    final updatedPurchasedSubscriptionInfo = _updateGooglePlayPurchasedSubscriptionInfoFromApiOne(
      purchasedSubscriptionInfo: purchasedSubscriptionInfo,
      updatedApiPurchasedSubscription: updatedApiPurchasedSubscription,
    );

    final purchasedSubscriptionTransaction =
        await _googlePlayTransactionRepository.findTransactionByOrderId(
      orderId: updatedApiPurchasedSubscription.orderId,
    ) as GooglePlayPurchasedSubscriptionTransaction?;

    GooglePlayPurchasedSubscriptionTransaction updatedPurchasedSubscriptionTransaction;

    if (purchasedSubscriptionTransaction == null) {
      final failureOrRevokedPurchasedItems =
          await _googlePlayApiPurchasedItemRepository.getRevokedPurchasedItems();

      if (failureOrRevokedPurchasedItems.isLeft()) {
        return left(const SubscriptionDeferredGooglePlayApiNotificationHandlingFailure());
      }

      final revokedPurchasedItems = failureOrRevokedPurchasedItems.asRight();

      GooglePlayApiRevokedPurchasedItem? correspondingRevokedPurchasedItem;

      for (final revokedPurchasedItem in revokedPurchasedItems) {
        if (revokedPurchasedItem.orderId == updatedApiPurchasedSubscription.orderId) {
          correspondingRevokedPurchasedItem = revokedPurchasedItem;
        }
      }

      updatedPurchasedSubscriptionTransaction =
          _createGooglePlayPurchasedSubscriptionTransactionFromApiOne(
        apiPurchasedSubscription: updatedApiPurchasedSubscription,
        purchaseItemSku: purchasedItemIdentifier.purchaseItemSku,
        purchaseToken: purchasedItemIdentifier.purchaseToken,
        googlePlayUserId: purchasedSubscriptionInfo.googlePlayUserId,
        revocationInfo: null,
      );

      if (correspondingRevokedPurchasedItem != null) {
        updatedPurchasedSubscriptionTransaction =
            _updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem(
          purchasedSubscriptionTransaction: updatedPurchasedSubscriptionTransaction,
          revokedPurchasedItem: correspondingRevokedPurchasedItem,
        );
      }
    } else {
      updatedPurchasedSubscriptionTransaction =
          _updateGooglePlayPurchasedSubscriptionTransactionFromApiOne(
        purchasedSubscriptionTransaction: purchasedSubscriptionTransaction,
        updatedApiPurchasedSubscription: updatedApiPurchasedSubscription,
      );
    }

    await Future.wait([
      _googlePlayPurchasedItemInfoRepository.upsertPurchasedItemInfo(
        purchasedItemInfo: updatedPurchasedSubscriptionInfo,
      ),
      _googlePlayTransactionRepository.upsertTransaction(
        purchasedItemTransaction: updatedPurchasedSubscriptionTransaction,
      ),
    ]);

    return right(null);
  }
}
